import { openWindow } from "./window";

interface DownloadOptions<T = string> {
  fileName?: string;
  source: T;
  target?: string;
}

const DEFAULT_FILENAME = "downloaded_file";

/**
 * 通过 URL 下载文件，支持跨域
 * @throws {Error} - 当下载失败时抛出错误
 */
export async function downloadFileFromUrl({ fileName, source, target = "_blank" }: DownloadOptions): Promise<void> {
  if (!source || typeof source !== "string") {
    throw new Error("Invalid URL.");
  }

  const isChrome = window.navigator.userAgent.toLowerCase().includes("chrome");
  const isSafari = window.navigator.userAgent.toLowerCase().includes("safari");

  if (/iP/.test(window.navigator.userAgent)) {
    console.error("Your browser does not support download!");
    return;
  }

  if (isChrome || isSafari) {
    triggerDownload(source, resolveFileName(source, fileName));
    return;
  }
  if (!source.includes("?")) {
    source += "?download";
  }

  openWindow(source, { target });
}

/**
 * 通过 Base64 下载文件
 */
export function downloadFileFromBase64({ fileName, source }: DownloadOptions) {
  if (!source || typeof source !== "string") {
    throw new Error("Invalid Base64 data.");
  }

  const resolvedFileName = fileName || DEFAULT_FILENAME;
  triggerDownload(source, resolvedFileName);
}

/**
 * 通过图片 URL 下载图片文件
 */
export async function downloadFileFromImageUrl({ fileName, source }: DownloadOptions) {
  const base64 = await urlToBase64(source);
  downloadFileFromBase64({ fileName, source: base64 });
}

/**
 * 通过 Blob 下载文件
 */
export function downloadFileFromBlob({ fileName = DEFAULT_FILENAME, source }: DownloadOptions<Blob>): void {
  if (!(source instanceof Blob)) {
    throw new TypeError("Invalid Blob data.");
  }

  const url = URL.createObjectURL(source);
  triggerDownload(url, fileName);
}

/**
 * 下载文件，支持 Blob、字符串和其他 BlobPart 类型
 */
export function downloadFileFromBlobPart({ fileName = DEFAULT_FILENAME, source }: DownloadOptions<BlobPart>): void {
  // 如果 data 不是 Blob，则转换为 Blob
  const blob = source instanceof Blob ? source : new Blob([source], { type: "application/octet-stream" });

  // 创建对象 URL 并触发下载
  const url = URL.createObjectURL(blob);
  triggerDownload(url, fileName);
}

/**
 * img url to base64
 * @param url
 */
export function urlToBase64(url: string, mineType?: string): Promise<string> {
  return new Promise((resolve, reject) => {
    let canvas = document.createElement("CANVAS") as HTMLCanvasElement | null;
    const ctx = canvas?.getContext("2d");
    const img = new Image();
    img.crossOrigin = "";
    img.addEventListener("load", () => {
      if (!canvas || !ctx) {
        return reject(new Error("Failed to create canvas."));
      }
      canvas.height = img.height;
      canvas.width = img.width;
      ctx.drawImage(img, 0, 0);
      const dataURL = canvas.toDataURL(mineType || "image/png");
      canvas = null;
      resolve(dataURL);
    });
    img.src = url;
  });
}

/**
 * 通用下载触发函数
 * @param href - 文件下载的 URL
 * @param fileName - 下载文件的名称，如果未提供则自动识别
 * @param revokeDelay - 清理 URL 的延迟时间 (毫秒)
 */
export function triggerDownload(href: string, fileName: string | undefined, revokeDelay: number = 100): void {
  const defaultFileName = "downloaded_file";
  const finalFileName = fileName || defaultFileName;

  const link = document.createElement("a");
  link.href = href;
  link.download = finalFileName;
  link.style.display = "none";

  if (link.download === undefined) {
    link.setAttribute("target", "_blank");
  }

  document.body.append(link);
  link.click();
  link.remove();

  // 清理临时 URL 以释放内存
  setTimeout(() => URL.revokeObjectURL(href), revokeDelay);
}

function resolveFileName(url: string, fileName?: string): string {
  return fileName || url.slice(url.lastIndexOf("/") + 1) || DEFAULT_FILENAME;
}
